#!/usr/bin/env python
# -*- coding: utf-8 -*-
# author：albert time:2021/9/2
import cv2
import mediapipe as mp
import math


class HandDiscem:
    """
    手势识别类
    """

    def __init__(self):
        self.gesture = ''
        # 窗口状态
        self.active = True

    @staticmethod
    def vector_2d_angle(v1, v2):
        """
        求解二维向量的角度
        """
        v1_x = v1[0]
        v1_y = v1[1]
        v2_x = v2[0]
        v2_y = v2[1]
        try:
            angle_ = math.degrees(math.acos((v1_x*v2_x+v1_y*v2_y)/(((v1_x**2+v1_y**2)**0.5)*((v2_x**2+v2_y**2)**0.5))))
        except Exception as e:
            # print(e)
            angle_ = 65535.
        if angle_ > 180.:
            angle_ = 65535.
        return angle_

    def hand_angle(self, hand_):
        """
        获取对应手相关向量的二维角度,根据角度确定手势
        """
        angle_list = []
        # ---------------------------- thumb 大拇指角度
        angle_ = self.vector_2d_angle(
            ((int(hand_[0][0]) - int(hand_[2][0])), (int(hand_[0][1]) - int(hand_[2][1]))),
            ((int(hand_[3][0]) - int(hand_[4][0])), (int(hand_[3][1]) - int(hand_[4][1])))
            )
        angle_list.append(angle_)
        # ---------------------------- index 食指角度
        angle_ = self.vector_2d_angle(
            ((int(hand_[0][0]) - int(hand_[6][0])), (int(hand_[0][1]) - int(hand_[6][1]))),
            ((int(hand_[7][0]) - int(hand_[8][0])), (int(hand_[7][1]) - int(hand_[8][1])))
            )
        angle_list.append(angle_)
        # ---------------------------- middle 中指角度
        angle_ = self.vector_2d_angle(
            ((int(hand_[0][0]) - int(hand_[10][0])), (int(hand_[0][1]) - int(hand_[10][1]))),
            ((int(hand_[11][0]) - int(hand_[12][0])), (int(hand_[11][1]) - int(hand_[12][1])))
            )
        angle_list.append(angle_)
        # ---------------------------- ring 无名指角度
        angle_ = self.vector_2d_angle(
            ((int(hand_[0][0]) - int(hand_[14][0])), (int(hand_[0][1]) - int(hand_[14][1]))),
            ((int(hand_[15][0]) - int(hand_[16][0])), (int(hand_[15][1]) - int(hand_[16][1])))
            )
        angle_list.append(angle_)
        # ---------------------------- pink 小拇指角度
        angle_ = self.vector_2d_angle(
            ((int(hand_[0][0]) - int(hand_[18][0])), (int(hand_[0][1]) - int(hand_[18][1]))),
            ((int(hand_[19][0]) - int(hand_[20][0])), (int(hand_[19][1]) - int(hand_[20][1])))
            )
        angle_list.append(angle_)
        return angle_list

    @staticmethod
    def h_gesture(angle_list):
        """
        二维约束的方法定义手势
        # fist five gun love one six three thumbUp yeah
        """
        thr_angle = 65.
        thr_angle_thumb = 53.
        thr_angle_s = 49.
        gesture_str = None
        if 65535. not in angle_list:
            if (angle_list[0] > thr_angle_thumb) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and \
                    (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):
                gesture_str = "fist"
            elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) and \
                    (angle_list[3] < thr_angle_s) and (angle_list[4] < thr_angle_s):
                gesture_str = "five"
            elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and \
                    (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):
                gesture_str = "gun"
            elif (angle_list[0] < thr_angle_s) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and \
                    (angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s):
                gesture_str = "love"
            elif (angle_list[0] > 5) and (angle_list[1] < thr_angle_s) and (angle_list[2] > thr_angle) and \
                    (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):
                gesture_str = "one"
            elif (angle_list[0] < thr_angle_s) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and \
                    (angle_list[3] > thr_angle) and (angle_list[4] < thr_angle_s):
                gesture_str = "six"
            elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) \
                    and (angle_list[3] < thr_angle_s) and (angle_list[4] > thr_angle):
                gesture_str = "three"
            elif (angle_list[0] < thr_angle_s) and (angle_list[1] > thr_angle) and (angle_list[2] > thr_angle) and \
                    (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):
                gesture_str = "thumbUp"
            elif (angle_list[0] > thr_angle_thumb) and (angle_list[1] < thr_angle_s) and (angle_list[2] < thr_angle_s) \
                    and (angle_list[3] > thr_angle) and (angle_list[4] > thr_angle):
                gesture_str = "two"
        return gesture_str

    def detect(self):
        mp_drawing = mp.solutions.drawing_utils
        mp_hands = mp.solutions.hands
        hands = mp_hands.Hands(
                static_image_mode=False,
                max_num_hands=1,
                min_detection_confidence=0.75,
                min_tracking_confidence=0.75)
        cap = cv2.VideoCapture(0)
        while True:
            ret, frame = cap.read()
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            frame = cv2.flip(frame, 1)
            results = hands.process(frame)
            frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)

            if results.multi_hand_landmarks:
                thr_angle = 65.
                thr_angle_thumb = 53.
                thr_angle_s = 49.
                for hand_landmarks in results.multi_hand_landmarks:
                    mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
                    hand_local = []
                    for i in range(21):
                        x = hand_landmarks.landmark[i].x*frame.shape[1]
                        y = hand_landmarks.landmark[i].y*frame.shape[0]
                        hand_local.append((x, y))
                    xd = hand_landmarks.landmark[4].x*frame.shape[1]-hand_landmarks.landmark[0].x*frame.shape[1]
                    yd = hand_landmarks.landmark[4].y*frame.shape[0]-hand_landmarks.landmark[0].y*frame.shape[0]
                    xyd = abs(xd)-abs(yd)
                    if (yd > 0) and (xyd < 0):
                        self.gesture = "down"
                    elif (yd < 0) and (xyd < 0):
                        self.gesture = "up"
                    elif (xd < 0) and (xyd > 0):
                        self.gesture = "left"
                    elif (xd > 0) and (xyd > 0):
                        self.gesture = "right"
                    # print(hand_landmarks.landmark[4].x*frame.shape[1],hand_landmarks.landmark[4].x*frame.shape[0])
                    if hand_local:
                        angle_list = self.hand_angle(hand_local)
                        gesture_str = self.h_gesture(angle_list)
                        cv2.putText(frame, gesture_str, (0, 100), 0, 1.3, (0, 0, 255), 3)
            cv2.imshow('MediaPipe Hands', frame)
            # if cv2.waitKey(1) & 0xFF == 27:
            #     break
            # 修改此处代码，解决点击关闭按钮不能关闭的BUG
            cv2.waitKey(1)
            if cv2.getWindowProperty('MediaPipe Hands', cv2.WND_PROP_VISIBLE) < 1:
                break
        cap.release()
        cv2.destroyAllWindows()
        self.active = False

